home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / chop next >
Encoding:
Internet Message Format  |  1991-11-25  |  10.3 KB

  1. Subject:  v25i001:  chop - extract selected fields or columns of text lines
  2. Newsgroups: comp.sources.unix
  3. Approved: vixie@pa.dec.com
  4.  
  5. Submitted-by: George L Sicherman <gls@hrmso.att.com>
  6. Posting-number: Volume 25, Issue 1
  7. Archive-name: chop
  8.  
  9. SYNOPSIS
  10.      chop -flist [ -dseparators ] [ -b ] [ file ... ]
  11.      chop -clist [ file ... ]
  12.  
  13. DESCRIPTION
  14.      Chop extracts selected fields or columns of lines from the
  15.      specified files or the standard input, and writes them to
  16.      the standard output.  If you specify -f, chop extracts
  17.      fields.  If you specify -c, chop extracts columns.
  18.  
  19. #! /bin/sh
  20. # This is a shell archive.  Remove anything before this line, then unpack
  21. # it by saving it into a file and typing "sh file".  To overwrite existing
  22. # files, type "sh file -c".  You can also feed this as standard input via
  23. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  24. # will see the following message at the end:
  25. #        "End of shell archive."
  26. # Contents:  chop.1 chop.c Makefile
  27. # Wrapped by vixie@cognition.pa.dec.com on Mon Nov 25 13:18:00 1991
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f 'chop.1' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'chop.1'\"
  31. else
  32. echo shar: Extracting \"'chop.1'\" \(2037 characters\)
  33. sed "s/^X//" >'chop.1' <<'END_OF_FILE'
  34. X.\" February 10, 1991.
  35. X.TH chop 1 Local
  36. X.UC 4
  37. X.SH NAME
  38. chop \- extract selected fields or columns of text lines
  39. X.SH SYNOPSIS
  40. X.B chop
  41. X.BR \-f list
  42. X[
  43. X.BR \-d separators
  44. X] [
  45. X.BR \-b
  46. X] [ file ... ]
  47. X.br
  48. X.B chop
  49. X.BR \-c list
  50. X[ file ... ]
  51. X.SH DESCRIPTION
  52. X.I Chop
  53. extracts selected fields or columns of lines from the specified files or the
  54. standard input,
  55. and writes them to the standard output.
  56. If you specify
  57. X.BR \-f ,
  58. X.I chop
  59. extracts fields.
  60. If you specify
  61. X.BR \-c ,
  62. X.I chop
  63. extracts columns.
  64. X.PP
  65. XFields and columns are numbered from 1.
  66. A list of fields or columns consists of one or more ranges
  67. separated by commas.
  68. A range is a single number or a minus sign with a number
  69. at one or both ends.
  70. An open range runs to the corresponding end of the line;
  71. for instance,
  72. X.B \-3
  73. is the same as
  74. X.BR 1\-3 ,
  75. and
  76. X.B 5\-
  77. means all fields or columns from 5 onward.
  78. An input line ends with a newline, a carriage return, or a form feed.
  79. X.PP
  80. XFor the
  81. X.B \-f
  82. option, the default input separator is white space, and the default
  83. output separator is the horizontal tab.
  84. Use the
  85. X.B \-d
  86. option to specify an alternate set of input separators;
  87. the first of them will be used on output.
  88. If you use the
  89. X.B \-d
  90. option, every occurrence of an input separator delimits a field.
  91. If you do not specify
  92. X.BR \-d ,
  93. leading white space in a line is normally ignored.
  94. To treat leading white space as a separator, specify
  95. X.BR \-b .
  96. X.PP
  97. XFor the
  98. X.B \-c
  99. option, a backspace character decrements the column,
  100. and a horizontal tab advances to the next standard 8-column tab stop.
  101. X.SH DIAGNOSTICS
  102. XExits with status 0 on success, 1 on invalid syntax,
  103. and 2 if it cannot read an argument file.
  104. X.SH NOTES
  105. X.I Chop
  106. is meant to improve on
  107. X.IR cut (1).
  108. It has no limit on input line width or backspacing,
  109. lets many characters be input separators at once,
  110. and accepts white space as an input separator.
  111. It is not wholly compatible with
  112. X.I cut;
  113. in particular, it processes
  114. X.I all
  115. input lines the same way.
  116. X.SH SEE ALSO
  117. cut(1), paste(1), awk(1)
  118. X.SH PROVIDER
  119. G. L. Sicherman  (odyssey\^!\^gls)
  120. END_OF_FILE
  121. if test 2037 -ne `wc -c <'chop.1'`; then
  122.     echo shar: \"'chop.1'\" unpacked with wrong size!
  123. fi
  124. # end of 'chop.1'
  125. fi
  126. if test -f 'chop.c' -a "${1}" != "-c" ; then 
  127.   echo shar: Will not clobber existing file \"'chop.c'\"
  128. else
  129. echo shar: Extracting \"'chop.c'\" \(5684 characters\)
  130. sed "s/^X//" >'chop.c' <<'END_OF_FILE'
  131. X/*
  132. X *    chop - chop selected fields out of text.
  133. X *    G. L. Sicherman.  August 7, 1990.  February 10, 1991.
  134. X *
  135. X *    chop -cLIST [file ...]
  136. X *    chop -fLIST [-dchar] [-b] [file ...]
  137. X *
  138. X *    Chop writes the specified fields (-f) or columns (-c)
  139. X *        to the standard output.
  140. X *    Default output field separator is horizontal tab.
  141. X *    Default field separator is white space;
  142. X *    -dx... specifies characters x... as input field separators
  143. X *    and the first x as output field separator.
  144. X *    If the input separator is white space, leading white space
  145. X *    is ignored unless you specify -b.
  146. X *
  147. X *    Unlike cut(1), chop processes *all* input lines as specified,
  148. X *    and a line can be as long as you like.
  149. X *
  150. X *    Carriage returns, line feeds, and form feeds all act as
  151. X *    line separators.  Other control characters (other than
  152. X *    separators) are treated as ordinary characters in fields.
  153. X *    In columns, BS is -1 column, HT jumps to a standard
  154. X *    8-column tab stop.
  155. X *
  156. X *    EXIT CODES:    0 on success;
  157. X *            1 on syntax errors;
  158. X *            2 on file access failures.
  159. X */
  160. X
  161. X#include <ctype.h>
  162. X#include <stdio.h>
  163. X#include <string.h>
  164. X
  165. char    *calloc();
  166. X
  167. X#define    INFINITY    (-1)
  168. X#define    DEFOUTSEP    '\t'
  169. X
  170. struct rangetype {
  171. X    int    first;
  172. X    int    last;
  173. X};
  174. X
  175. static    int    bflag = 0;
  176. static    char    *cflag = (char *)NULL;
  177. static    char    *dflag = (char *)NULL;
  178. static    char    *fflag = (char *)NULL;
  179. static    FILE    *Input;
  180. static    int    nranges;
  181. static    char    *progn;
  182. static    struct    rangetype    *range;
  183. static    int    (*process)();
  184. static    int    cprocess(), fprocess();
  185. X
  186. usage()
  187. X{
  188. X    fprintf(stderr, "usage: %s -cLIST [file ...]\n", progn);
  189. X    fprintf(stderr, "       %s -fLIST [-dCHARS] [-b] [file ...]\n", progn);
  190. X    exit(1);
  191. X}
  192. X
  193. main(argc, argv)
  194. int    argc;
  195. char    **argv;
  196. X{
  197. X    progn = *argv;
  198. X    while (--argc) {
  199. X        if ('-'!=**++argv) break;
  200. X        switch(*++*argv) {
  201. X        case 'b':
  202. X            bflag = 1;
  203. X            break;
  204. X        case 'c':
  205. X            if (!*(cflag = ++*argv)) {
  206. X                fprintf(stderr,
  207. X                "%s: column list required after -c\n", progn);
  208. X                exit(1);
  209. X            }
  210. X            break;
  211. X        case 'd':
  212. X            if (!*(dflag = ++*argv)) {
  213. X                fprintf(stderr,
  214. X                "%s: character required after -d\n", progn);
  215. X                exit(1);
  216. X            }
  217. X            break;
  218. X        case 'f':
  219. X            if (!*(fflag = ++*argv)) {
  220. X                fprintf(stderr,
  221. X                "%s: field list required after -f\n", progn);
  222. X                exit(1);
  223. X            }
  224. X            break;
  225. X        default:
  226. X            usage();
  227. X        }
  228. X    }
  229. X    if (!fflag == !cflag) usage();
  230. X    if (cflag) {
  231. X        process = cprocess;
  232. X        setupranges(cflag);
  233. X    }
  234. X    else {
  235. X        process = fprocess;
  236. X        setupranges(fflag);
  237. X    }
  238. X    if (cflag && dflag) fprintf(stderr, "%s: -d option ignored with -c\n",
  239. X        progn);
  240. X    if (cflag && bflag) fprintf(stderr, "%s: -b option ignored with -c\n",
  241. X        progn);
  242. X    if (fflag && dflag && bflag) {
  243. X        fprintf(stderr, "%s: -b option ignored with -d\n", progn);
  244. X        bflag = 0;
  245. X    }
  246. X    if (argc) while (argc--) {
  247. X        Input = fopen(*argv++, "r");
  248. X        if (!Input) {
  249. X            fprintf(stderr, "%s: cannot read %s\n",
  250. X                progn, *--argv);
  251. X            exit(2);
  252. X        }
  253. X        (*process)(Input);
  254. X        fclose(Input);
  255. X    }
  256. X    else (*process)(stdin);
  257. X}
  258. X
  259. X/*
  260. X *    chop -c
  261. X */
  262. static    int    incol, outcol;
  263. X
  264. static int
  265. cprocess(stream)
  266. XFILE    *stream;
  267. X{
  268. X    int    k;
  269. X
  270. X    incol = outcol = 0;
  271. X    for (;;) {
  272. X        switch(k = getc(stream)) {
  273. X        case EOF:    return;
  274. X        case '\b':    if (!incol--) incol = 0;
  275. X                break;
  276. X        case '\t':    incol = (incol+8)&~7;
  277. X                break;
  278. X        case '\n':
  279. X        case '\r':
  280. X        case '\f':    catchup();
  281. X                putchar(k);
  282. X                incol = outcol = 0;
  283. X                break;
  284. X        default:
  285. X                catchup();
  286. X                if (wantit(++outcol)) putchar(k);
  287. X                incol++;
  288. X        }
  289. X    }
  290. X}
  291. X
  292. catchup()
  293. X{
  294. X    while (incol > outcol) if (wantit(++outcol)) putchar(' ');
  295. X    while (incol < outcol) if (wantit(outcol--)) putchar('\b');
  296. X}
  297. X
  298. X/*
  299. X *    chop -f
  300. X */
  301. X
  302. static int
  303. fprocess(stream)
  304. XFILE    *stream;
  305. X{
  306. X    int    field, go;
  307. X    int    k;
  308. X    int    later;
  309. X    char    *seps;
  310. X    int    want;
  311. X
  312. X    field = later = 0;
  313. X    seps = dflag? dflag: "\t ";
  314. X    for (;;) {
  315. newfield:
  316. X        field++;
  317. X        go = 0;
  318. X        want = wantit(field);
  319. X        if (want && later++) putchar(*seps);
  320. X        for (;;) {            /* process one field */
  321. X            k = getc(stream);
  322. X            if (EOF==k) return;
  323. X            if (strchr(seps, k)) {
  324. X                if (field==1 && !go
  325. X                && !dflag && !bflag) continue;
  326. X                else break;
  327. X            }
  328. X            if (strchr("\n\r\f", k)) {
  329. X                putchar(k);
  330. X                field = later = 0;
  331. X                goto newfield;    /* i.e., break 2 */
  332. X            }
  333. X            go = 1;
  334. X            if (want) putchar(k);
  335. X        }
  336. X/*
  337. X *        If white space, skip it.
  338. X */
  339. X        if (!dflag) for (;;) {
  340. X            k = getc(stream);
  341. X            if (EOF==k) {
  342. X                putchar(*seps);
  343. X                return;
  344. X            }
  345. X            if (strchr(seps, k)) continue;
  346. X            ungetc(k, stream);
  347. X            break;
  348. X        }
  349. X    }
  350. X}
  351. X
  352. int
  353. wantit(f)
  354. int    f;
  355. X{
  356. X    int    r;
  357. X
  358. X    for (r=0; r<nranges; r++) {
  359. X        if (range[r].last != INFINITY && range[r].last < f) continue;
  360. X        if (range[r].first <= f) return 1;
  361. X    }
  362. X    return 0;
  363. X}
  364. X
  365. setupranges(list)
  366. char    *list;
  367. X{
  368. X    char    *cursor;
  369. X/*
  370. X *    How many commas?
  371. X */
  372. X    nranges = 1;
  373. X    for (cursor = list; *cursor; cursor++)
  374. X        if (',' == *cursor) nranges++;
  375. X    range = (struct rangetype *)calloc(nranges, sizeof(struct rangetype));
  376. X    nranges = 0;
  377. X    for (cursor = list; cursor; ) {
  378. X        onerange(cursor);
  379. X        if (cursor = strchr(cursor,',')) cursor++;
  380. X    }
  381. X}
  382. X
  383. onerange(r)
  384. char    *r;
  385. X{
  386. X    if (isdigit(*r)) {
  387. X        range[nranges].first = atoi(r);
  388. X        while (isdigit(*r)) r++;
  389. X        if (','==*r || !*r) {
  390. X            range[nranges].last = range[nranges].first;
  391. X            nranges++;
  392. X            return;
  393. X        }
  394. X        if ('-'!=*r++) {
  395. X            fprintf(stderr,
  396. X                "%s: bad character '%c' in field list\n",
  397. X                progn, *--r);
  398. X            exit(1);
  399. X        }
  400. X    }
  401. X    else if ('-'==*r++) {
  402. X        range[nranges].first = 1;
  403. X    }
  404. X    else {
  405. X        fprintf(stderr, "%s: bad character '%c' in field list\n",
  406. X            progn, *--r);
  407. X        exit(1);
  408. X    }
  409. X    if (','==*r || !*r) {
  410. X        range[nranges++].last = INFINITY;
  411. X        return;
  412. X    }
  413. X    if (!isdigit(*r)) {
  414. X        fprintf(stderr, "%s: bad character '%c' in field list\n",
  415. X            progn, *r);
  416. X        exit(1);
  417. X    }
  418. X    range[nranges++].last = atoi(r);
  419. X    while (isdigit(*r)) r++;
  420. X    if (*r && ','!=*r) {
  421. X        fprintf(stderr, "%s: bad character '%c' in field list\n",
  422. X            progn, *r);
  423. X        exit(1);
  424. X    }
  425. X}
  426. END_OF_FILE
  427. if test 5684 -ne `wc -c <'chop.c'`; then
  428.     echo shar: \"'chop.c'\" unpacked with wrong size!
  429. fi
  430. # end of 'chop.c'
  431. fi
  432. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  433.   echo shar: Will not clobber existing file \"'Makefile'\"
  434. else
  435. echo shar: Extracting \"'Makefile'\" \(291 characters\)
  436. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  437. BINDEST=$$HOME/lubin/chop
  438. MANDEST=$$HOME/luman/chop.1
  439. X
  440. CFLAGS = -O
  441. chop : chop.o
  442. X    cc -o chop chop.o
  443. install : chop chop.1
  444. X    cp chop $(BINDEST)
  445. X    cp chop.1 $(MANDEST)
  446. shar : chop.shar
  447. chop.shar : Makefile chop.1 chop.c
  448. X    shar Makefile chop.1 chop.c > chop.shar
  449. clean :
  450. X    rm -f chop chop.shar *.o
  451. END_OF_FILE
  452. if test 291 -ne `wc -c <'Makefile'`; then
  453.     echo shar: \"'Makefile'\" unpacked with wrong size!
  454. fi
  455. # end of 'Makefile'
  456. fi
  457. echo shar: End of shell archive.
  458. exit 0
  459.